# Copies # {#copies}

## Buffer Copies ## {#buffer-copies}

Buffer copy operations operate on raw bytes.

WebGPU provides "buffered" {{GPUCommandEncoder}} commands:

- {{GPUCommandEncoder/copyBufferToBuffer()}}
- {{GPUCommandEncoder/clearBuffer()}}

and "immediate" {{GPUQueue}} operations:

- {{GPUQueue/writeBuffer()}}, for {{ArrayBuffer}}-to-{{GPUBuffer}} writes

## Image Copies ## {#image-copies}

<dfn dfn>Image copy</dfn> operations operate on texture/"image" data, rather than bytes.

WebGPU provides "buffered" {{GPUCommandEncoder}} commands:

- {{GPUCommandEncoder/copyTextureToTexture()}}
- {{GPUCommandEncoder/copyBufferToTexture()}}
- {{GPUCommandEncoder/copyTextureToBuffer()}}

and "immediate" {{GPUQueue}} operations:

- {{GPUQueue/writeTexture()}}, for {{ArrayBuffer}}-to-{{GPUTexture}} writes
- {{GPUQueue/copyExternalImageToTexture()}}, for copies from Web Platform image sources to textures

Some texel values have <dfn dfn lt='equivalent texel representation'>multiple possible representations</dfn>
of some values, e.g. as `r8snorm`, -1.0 can be represented as either -127 or -128.
Copy commands are not guaranteed to preserve the source's bit-representation.

The following definitions are used by these methods:

<h4 id=gpuimagedatalayout data-dfn-type=dictionary>`GPUImageDataLayout`
<span id=gpu-image-data-layout></span>
</h4>

<script type=idl>
dictionary GPUImageDataLayout {
    GPUSize64 offset = 0;
    GPUSize32 bytesPerRow;
    GPUSize32 rowsPerImage;
};
</script>

A <dfn dfn>texel image</dfn> is comprised of one or more rows of [=texel blocks=], referred to here
as <dfn dfn>texel block row</dfn>s. Each [=texel block row=] of a [=texel image=] must contain the
same number of [=texel blocks=], and all [=texel blocks=] in a [=texel image=] are of the same
{{GPUTextureFormat}}.

A {{GPUImageDataLayout}} is a layout of [=texel images=] within some linear memory.
It's used when copying data between a [=texture=] and a {{GPUBuffer}}, or when scheduling a
write into a [=texture=] from the {{GPUQueue}}.

- For {{GPUTextureDimension/2d}} textures, data is copied between one or multiple contiguous
    [=texel images=] and [=array layers=].
- For {{GPUTextureDimension/3d}} textures, data is copied between one or multiple contiguous
    [=texel images=] and depth [=slices=].

Operations that copy between byte arrays and textures always operate on whole [=texel block=].
It's not possible to update only a part of a [=texel block=].

[=Texel blocks=] are tightly packed within each [=texel block row=] in the linear memory layout of an
image copy, with each subsequent [=texel block=] immediately following the previous [=texel block=],
with no padding.
This includes [[#copying-depth-stencil|copies]] to/from specific aspects of [=depth-or-stencil format=] textures:
stencil values are tightly packed in an array of bytes;
depth values are tightly packed in an array of the appropriate type ("depth16unorm" or "depth32float").

<dl dfn-type=dict-member dfn-for=GPUImageDataLayout>
    : <dfn>offset</dfn>
    ::
        The offset, in bytes, from the beginning of the image data source (such as a
        {{GPUImageCopyBuffer/buffer|GPUImageCopyBuffer.buffer}}) to the start of the image data
        within that source.

    : <dfn>bytesPerRow</dfn>
    ::
        The stride, in bytes, between the beginning of each [=texel block row=] and the subsequent
        [=texel block row=].

        Required if there are multiple [=texel block rows=] (i.e. the copy height or depth is more
        than one block).

    : <dfn>rowsPerImage</dfn>
    ::
        Number of [=texel block rows=] per single [=texel image=] of the [=texture=].
        {{GPUImageDataLayout/rowsPerImage}} &times;
        {{GPUImageDataLayout/bytesPerRow}} is the stride, in bytes, between the beginning of each
        [=texel image=] of data and the subsequent [=texel image=].

        Required if there are multiple [=texel images=] (i.e. the copy depth is more than one).
</dl>

<h4 id=gpuimagecopybuffer data-dfn-type=dictionary>`GPUImageCopyBuffer`
<span id=gpu-image-copy-buffer></span>
</h4>

In an [=image copy=] operation, {{GPUImageCopyBuffer}} defines a {{GPUBuffer}} and, together with
the `copySize`, how image data is laid out in the buffer's memory (see {{GPUImageDataLayout}}).

<script type=idl>
dictionary GPUImageCopyBuffer
         : GPUImageDataLayout {
    required GPUBuffer buffer;
};
</script>

<dl dfn-type=dict-member dfn-for=GPUImageCopyBuffer>
    : <dfn>buffer</dfn>
    ::
        A buffer which either contains image data to be copied or will store the image data being
        copied, depending on the method it is being passed to.
</dl>

<div algorithm data-timeline=device>
    <dfn abstract-op>validating GPUImageCopyBuffer</dfn>

    **Arguments:**

    - {{GPUImageCopyBuffer}} |imageCopyBuffer|

    **Returns:** {{boolean}}

    [=Device timeline=] steps:

    1. Return `true` if and only if all of the following conditions are satisfied:

        <div class=validusage>
            - |imageCopyBuffer|.{{GPUImageCopyBuffer/buffer}} must be a [=valid=] {{GPUBuffer}}.
            - |imageCopyBuffer|.{{GPUImageDataLayout/bytesPerRow}} must be a multiple of 256.
        </div>
</div>

<h4 id=gpuimagecopytexture data-dfn-type=dictionary>`GPUImageCopyTexture`
<span id=gpu-image-copy-texture></span>
</h4>

In an [=image copy=] operation, a {{GPUImageCopyTexture}} defines a {{GPUTexture}} and, together with
the `copySize`, the sub-region of the texture (spanning one or more contiguous
[=texture subresources=] at the same mip-map level).

<script type=idl>
dictionary GPUImageCopyTexture {
    required GPUTexture texture;
    GPUIntegerCoordinate mipLevel = 0;
    GPUOrigin3D origin = {};
    GPUTextureAspect aspect = "all";
};
</script>

<dl dfn-type=dict-member dfn-for=GPUImageCopyTexture>
    : <dfn>texture</dfn>
    ::
        Texture to copy to/from.

    : <dfn>mipLevel</dfn>
    ::
        Mip-map level of the {{GPUImageCopyTexture/texture}} to copy to/from.

    : <dfn>origin</dfn>
    ::
        Defines the origin of the copy - the minimum corner of the texture sub-region to copy to/from.
        Together with `copySize`, defines the full copy sub-region.

    : <dfn>aspect</dfn>
    ::
        Defines which aspects of the {{GPUImageCopyTexture/texture}} to copy to/from.
</dl>

<div algorithm data-timeline=const>
    The <dfn abstract-op>texture copy sub-region</dfn> for depth slice or array layer |index| of {{GPUImageCopyTexture}}
    |copyTexture| is determined by running the following steps:

        1. Let |texture| be |copyTexture|.{{GPUImageCopyTexture/texture}}.
        1. If |texture|.{{GPUTexture/dimension}} is:
            <dl class=switch>
                : {{GPUTextureDimension/1d}}
                ::  1. [=Assert=] |index| is `0`
                    1. Let |depthSliceOrLayer| be |texture|

                : {{GPUTextureDimension/2d}}
                :: Let |depthSliceOrLayer| be array layer |index| of |texture|

                : {{GPUTextureDimension/3d}}
                :: Let |depthSliceOrLayer| be depth slice |index| of |texture|
            </dl>
        1. Let |textureMip| be mip level |copyTexture|.{{GPUImageCopyTexture/mipLevel}} of |depthSliceOrLayer|.
        1. Return aspect |copyTexture|.{{GPUImageCopyTexture/aspect}} of |textureMip|.
</div>

<div algorithm data-timeline=const>
    The <dfn abstract-op>texel block byte offset</dfn> of data described by {{GPUImageDataLayout}} |dataLayout|
    corresponding to [=texel block=] |x|, |y| of depth slice or array layer |z| of a {{GPUTexture}} |texture| is
    determined by running the following steps:

        1. Let |blockBytes| be the [=texel block copy footprint=] of |texture|.{{GPUTexture/format}}.
        1. Let |imageOffset| be (|z| &times; |dataLayout|.{{GPUImageDataLayout/rowsPerImage}} &times;
            |dataLayout|.{{GPUImageDataLayout/bytesPerRow}}) &plus; |dataLayout|.{{GPUImageDataLayout/offset}}.
        1. Let |rowOffset| be (|y| &times; |dataLayout|.{{GPUImageDataLayout/bytesPerRow}}) &plus; |imageOffset|.
        1. Let |blockOffset| be (|x| &times; |blockBytes|) &plus; |rowOffset|.
        1. Return |blockOffset|.
</div>

<div algorithm data-timeline=device>
    <dfn abstract-op>validating GPUImageCopyTexture</dfn>(|imageCopyTexture|, |copySize|)

    **Arguments:**

    - {{GPUImageCopyTexture}} |imageCopyTexture|
    - {{GPUExtent3D}} |copySize|

    **Returns:** {{boolean}}

    [=Device timeline=] steps:

    1. Let |blockWidth| be the [=texel block width=] of |imageCopyTexture|.{{GPUImageCopyTexture/texture}}.{{GPUTexture/format}}.
    1. Let |blockHeight| be the [=texel block height=] of |imageCopyTexture|.{{GPUImageCopyTexture/texture}}.{{GPUTexture/format}}.

    1. Return `true` if and only if all of the following conditions apply:

        <div class=validusage>
            - [$validating texture copy range$](|imageCopyTexture|, |copySize|) returns `true`.
            - |imageCopyTexture|.{{GPUImageCopyTexture/texture}} must be a [=valid=] {{GPUTexture}}.
            - |imageCopyTexture|.{{GPUImageCopyTexture/mipLevel}} must be &lt;
                |imageCopyTexture|.{{GPUImageCopyTexture/texture}}.{{GPUTexture/mipLevelCount}}.
            - |imageCopyTexture|.{{GPUImageCopyTexture/origin}}.[=GPUOrigin3D/x=] must be a multiple of |blockWidth|.
            - |imageCopyTexture|.{{GPUImageCopyTexture/origin}}.[=GPUOrigin3D/y=] must be a multiple of |blockHeight|.
            - The [=imageCopyTexture physical subresource size=] of |imageCopyTexture| is equal to |copySize| if either of
                the following conditions is true:
                - |imageCopyTexture|.{{GPUImageCopyTexture/texture}}.{{GPUTexture/format}} is a depth-stencil format.
                - |imageCopyTexture|.{{GPUImageCopyTexture/texture}}.{{GPUTexture/sampleCount}} &gt; 1.
        </div>
</div>

<div algorithm data-timeline=device>
    <dfn abstract-op>validating texture buffer copy</dfn>(|imageCopyTexture|, |dataLayout|, |dataLength|, |copySize|, |textureUsage|, |aligned|)

    **Arguments:**

    - {{GPUImageCopyTexture}} |imageCopyTexture|
    - {{GPUImageDataLayout}} |dataLayout|
    - {{GPUSize64Out}} |dataLength|
    - {{GPUExtent3D}} |copySize|
    - {{GPUTextureUsage}} |textureUsage|
    - {{boolean}} |aligned|

    **Returns:** {{boolean}}

    [=Device timeline=] steps:

    1. Let |texture| be |imageCopyTexture|.{{GPUImageCopyTexture/texture}}
    1. Let |aspectSpecificFormat| = |texture|.{{GPUTexture/format}}.
    1. Let |offsetAlignment| = [=texel block copy footprint=] of |texture|.{{GPUTexture/format}}.

    1. Return `true` if and only if all of the following conditions apply:

        <div class=validusage>
            1. [$validating GPUImageCopyTexture$](|imageCopyTexture|, |copySize|) returns `true`.
            1. |texture|.{{GPUTexture/sampleCount}} is 1.
            1. |texture|.{{GPUTexture/usage}} contains |textureUsage|.
            1. If |texture|.{{GPUTexture/format}} is a [=depth-or-stencil format=] format:
                1. |imageCopyTexture|.{{GPUImageCopyTexture/aspect}} must refer to a single aspect of
                    |texture|.{{GPUTexture/format}}.
                1. If |textureUsage| is:
                    <dl class=switch>
                        : {{GPUTextureUsage/COPY_SRC}}
                        :: That aspect must be a valid image copy source according to [[#depth-formats]].

                        : {{GPUTextureUsage/COPY_DST}}
                        :: That aspect must be a valid image copy destination according to [[#depth-formats]].
                    </dl>
                1. Set |aspectSpecificFormat| to the [=aspect-specific format=] according to [[#depth-formats]].
                1. Set |offsetAlignment| to 4.
            1. If |aligned| is `true`:
                1. |dataLayout|.{{GPUImageDataLayout/offset}} is a multiple of |offsetAlignment|.
            1. [$validating linear texture data$](|dataLayout|,
                |dataLength|,
                |aspectSpecificFormat|,
                |copySize|) succeeds.
        </div>
</div>

<h4 id=gpuimagecopytexturetagged data-dfn-type=dictionary>`GPUImageCopyTextureTagged`
<span id=gpu-image-copy-texture-tagged></span>
</h4>

WebGPU textures hold raw numeric data, and are not tagged with semantic metadata describing colors.
However, {{GPUQueue/copyExternalImageToTexture()}} copies from sources that describe colors.

A {{GPUImageCopyTextureTagged}} is a {{GPUImageCopyTexture}} which is additionally tagged with
color space/encoding and alpha-premultiplication metadata, so that semantic color data may be
preserved during copies.
This metadata affects only the semantics of the {{GPUQueue/copyExternalImageToTexture()}}
operation, not the semantics of the destination texture.

<script type=idl>
dictionary GPUImageCopyTextureTagged
         : GPUImageCopyTexture {
    PredefinedColorSpace colorSpace = "srgb";
    boolean premultipliedAlpha = false;
};
</script>

<dl dfn-type=dict-member dfn-for=GPUImageCopyTextureTagged>
    : <dfn>colorSpace</dfn>
    ::
        Describes the color space and encoding used to encode data into the destination texture.

        This [[#color-space-conversions|may result]] in values outside of the range [0, 1]
        being written to the target texture, if its format can represent them.
        Otherwise, the results are clamped to the target texture format's range.

        Note:
        If {{GPUImageCopyTextureTagged/colorSpace}} matches the source image,
        conversion may not be necessary. See [[#color-space-conversion-elision]].

    : <dfn>premultipliedAlpha</dfn>
    ::
        Describes whether the data written into the texture should have its RGB channels
        premultiplied by the alpha channel, or not.

        If this option is set to `true` and the {{GPUImageCopyExternalImage/source}} is also
        premultiplied, the source RGB values must be preserved even if they exceed their
        corresponding alpha values.

        Note:
        If {{GPUImageCopyTextureTagged/premultipliedAlpha}} matches the source image,
        conversion may not be necessary. See [[#color-space-conversion-elision]].
</dl>

<h4 id=gpuimagecopyexternalimage data-dfn-type=dictionary>`GPUImageCopyExternalImage`
<span id=gpu-image-copy-external-image></span>
</h4>

<script type=idl>
typedef (ImageBitmap or
         ImageData or
         HTMLImageElement or
         HTMLVideoElement or
         VideoFrame or
         HTMLCanvasElement or
         OffscreenCanvas) GPUImageCopyExternalImageSource;

dictionary GPUImageCopyExternalImage {
    required GPUImageCopyExternalImageSource source;
    GPUOrigin2D origin = {};
    boolean flipY = false;
};
</script>

{{GPUImageCopyExternalImage}} has the following members:

<dl dfn-type=dict-member dfn-for=GPUImageCopyExternalImage>
    : <dfn>source</dfn>
    ::
        The source of the [=image copy=]. The copy source data is captured at the moment that
        {{GPUQueue/copyExternalImageToTexture()}} is issued. Source size is determined as described
        by the [=external source dimensions=] table.

    : <dfn>origin</dfn>
    ::
        Defines the origin of the copy - the minimum (top-left) corner of the source sub-region to copy from.
        Together with `copySize`, defines the full copy sub-region.

    : <dfn>flipY</dfn>
    ::
        Describes whether the source image is vertically flipped, or not.

        If this option is set to `true`, the copy is flipped vertically: the bottom row of the source
        region is copied into the first row of the destination region, and so on.
        The {{GPUImageCopyExternalImage/origin}} option is still relative to the top-left corner
        of the source image, increasing downward.
</dl>

When external sources are used when creating or copying to textures, the <dfn dfn>external source dimensions</dfn>
are defined by the source type, given by this table:

<table class=data>
    <thead>
        <tr>
            <th>External Source type
            <th>Dimensions
    </thead>
    <tbody>
        <tr>
            <td>{{ImageBitmap}}
            <td>{{ImageBitmap/width|ImageBitmap.width}},
                {{ImageBitmap/height|ImageBitmap.height}}
        <tr>
            <td>{{HTMLImageElement}}
            <td>{{HTMLImageElement/naturalWidth|HTMLImageElement.naturalWidth}},
                {{HTMLImageElement/naturalHeight|HTMLImageElement.naturalHeight}}
        <tr>
            <td>{{HTMLVideoElement}}
            <td>[=video/intrinsic width|intrinsic width of the frame=],
                [=video/intrinsic height|intrinsic height of the frame=]
        <tr>
            <td>{{VideoFrame}}
            <td>{{VideoFrame/displayWidth|VideoFrame.displayWidth}},
                {{VideoFrame/displayHeight|VideoFrame.displayHeight}}
        <tr>
            <td>{{ImageData}}
            <td>{{ImageData/width|ImageData.width}},
                {{ImageData/height|ImageData.height}}
        <tr>
            <td>{{HTMLCanvasElement}} or {{OffscreenCanvas}} with {{CanvasRenderingContext2D}} or {{GPUCanvasContext}}
            <td>{{HTMLCanvasElement/width|HTMLCanvasElement.width}},
                {{HTMLCanvasElement/height|HTMLCanvasElement.height}}
        <tr>
            <td>{{HTMLCanvasElement}} or {{OffscreenCanvas}} with {{WebGLRenderingContextBase}}
            <td>{{WebGLRenderingContextBase/drawingBufferWidth|WebGLRenderingContextBase.drawingBufferWidth}},
                {{WebGLRenderingContextBase/drawingBufferHeight|WebGLRenderingContextBase.drawingBufferHeight}}
        <tr>
            <td>{{HTMLCanvasElement}} or {{OffscreenCanvas}} with {{ImageBitmapRenderingContext}}
            <td>{{ImageBitmapRenderingContext}}'s internal output bitmap
                {{ImageBitmap/width|ImageBitmap.width}},
                {{ImageBitmap/height|ImageBitmap.height}}
    </tbody>
</table>

### Subroutines ### {#image-copies-subroutines}

<div algorithm="imageCopyTexture physical subresource size" data-timeline=const>
    <dfn dfn>imageCopyTexture physical subresource size</dfn>

    **Arguments:**

    - {{GPUImageCopyTexture}} |imageCopyTexture|

    **Returns:** {{GPUExtent3D}}

    The [=imageCopyTexture physical subresource size=] of |imageCopyTexture| is calculated as follows:

    Its [=GPUExtent3D/width=], [=GPUExtent3D/height=] and [=GPUExtent3D/depthOrArrayLayers=] are the width, height, and depth, respectively,
    of the [=physical miplevel-specific texture extent=] of |imageCopyTexture|.{{GPUImageCopyTexture/texture}} [=subresource=] at [=mipmap level=]
    |imageCopyTexture|.{{GPUImageCopyTexture/mipLevel}}.
</div>

<div algorithm data-timeline=device>
    <dfn abstract-op>validating linear texture data</dfn>(layout, byteSize, format, copyExtent)

    **Arguments:**

    : {{GPUImageDataLayout}} |layout|
    :: Layout of the linear texture data.
    : {{GPUSize64}} |byteSize|
    :: Total size of the linear data, in bytes.
    : {{GPUTextureFormat}} |format|
    :: Format of the texture.
    : {{GPUExtent3D}} |copyExtent|
    :: Extent of the texture to copy.

    [=Device timeline=] steps:

    1. Let:
        - |widthInBlocks| be |copyExtent|.[=GPUExtent3D/width=] &divide; the [=texel block width=] of |format|.
            [=Assert=] this is an integer.
        - |heightInBlocks| be |copyExtent|.[=GPUExtent3D/height=] &divide; the [=texel block height=] of |format|.
            [=Assert=] this is an integer.
        - |bytesInLastRow| be |widthInBlocks| &times; the [=texel block copy footprint=] of |format|.
    1. Fail if the following input validation requirements are not met:

        <div class=validusage>
            - If |heightInBlocks| &gt; 1,
                |layout|.{{GPUImageDataLayout/bytesPerRow}} must be specified.
            - If |copyExtent|.[=GPUExtent3D/depthOrArrayLayers=] &gt; 1,
                |layout|.{{GPUImageDataLayout/bytesPerRow}} and
                |layout|.{{GPUImageDataLayout/rowsPerImage}} must be specified.
            - If specified, |layout|.{{GPUImageDataLayout/bytesPerRow}}
                must be &ge; |bytesInLastRow|.
            - If specified, |layout|.{{GPUImageDataLayout/rowsPerImage}}
                must be &ge; |heightInBlocks|.
        </div>
    1. Let:
        - |bytesPerRow| be |layout|.{{GPUImageDataLayout/bytesPerRow}} ?? 0.
        - |rowsPerImage| be |layout|.{{GPUImageDataLayout/rowsPerImage}} ?? 0.

        Note: These default values have no effect, as they're always multiplied by 0.
    1. Let |requiredBytesInCopy| be 0.
    1. If |copyExtent|.[=GPUExtent3D/depthOrArrayLayers=] &gt; 0:
        1. Increment |requiredBytesInCopy| by
            |bytesPerRow| &times; |rowsPerImage| &times; (|copyExtent|.[=GPUExtent3D/depthOrArrayLayers=] &minus; 1).
        1. If |heightInBlocks| &gt; 0:
            1. Increment |requiredBytesInCopy| by
                |bytesPerRow| &times; (|heightInBlocks| &minus; 1) + |bytesInLastRow|.
    1. Fail if the following condition is not satisfied:

        <div class=validusage>
            - The layout fits inside the linear data:
                |layout|.{{GPUImageDataLayout/offset}} + |requiredBytesInCopy| &le; |byteSize|.
        </div>
</div>

<div algorithm data-timeline=device>
    <dfn abstract-op>validating texture copy range</dfn>

    **Arguments:**

    : {{GPUImageCopyTexture}} |imageCopyTexture|
    :: The texture subresource being copied into and copy origin.
    : {{GPUExtent3D}} |copySize|
    :: The size of the texture.

    [=Device timeline=] steps:

    1. Let |blockWidth| be the [=texel block width=] of |imageCopyTexture|.{{GPUImageCopyTexture/texture}}.{{GPUTexture/format}}.
    1. Let |blockHeight| be the [=texel block height=] of |imageCopyTexture|.{{GPUImageCopyTexture/texture}}.{{GPUTexture/format}}.
    1. Let |subresourceSize| be the [=imageCopyTexture physical subresource size=] of |imageCopyTexture|.
    1. Return whether all the conditions below are satisfied:

        <div class=validusage>
            - (|imageCopyTexture|.{{GPUImageCopyTexture/origin}}.[=GPUOrigin3D/x=] + |copySize|.[=GPUExtent3D/width=]) &le; |subresourceSize|.[=GPUExtent3D/width=]
            - (|imageCopyTexture|.{{GPUImageCopyTexture/origin}}.[=GPUOrigin3D/y=] + |copySize|.[=GPUExtent3D/height=]) &le; |subresourceSize|.[=GPUExtent3D/height=]
            - (|imageCopyTexture|.{{GPUImageCopyTexture/origin}}.[=GPUOrigin3D/z=] + |copySize|.[=GPUExtent3D/depthOrArrayLayers=]) &le; |subresourceSize|.[=GPUExtent3D/depthOrArrayLayers=]
            - |copySize|.[=GPUExtent3D/width=] must be a multiple of |blockWidth|.
            - |copySize|.[=GPUExtent3D/height=] must be a multiple of |blockHeight|.

            Note:
            The texture copy range is validated against the *physical* (rounded-up)
            size for [=compressed formats=], allowing copies to access texture
            blocks which are not fully inside the texture.
        </div>
</div>

<div algorithm data-timeline=const>
    Two {{GPUTextureFormat}}s |format1| and |format2| are <dfn dfn>copy-compatible</dfn> if:

    - |format1| equals |format2|, or
    - |format1| and |format2| differ only in whether they are `srgb` formats (have the `-srgb` suffix).
</div>

<div algorithm data-timeline=const>
    The <dfn abstract-op>set of subresources for texture copy</dfn>(|imageCopyTexture|, |copySize|)
    is the subset of subresources of |texture| = |imageCopyTexture|.{{GPUImageCopyTexture/texture}}
    for which each subresource |s| satisfies the following:

    - The [=mipmap level=] of |s| equals
        |imageCopyTexture|.{{GPUImageCopyTexture/mipLevel}}.
    - The [=aspect=] of |s| is in the [=GPUTextureAspect/set of aspects=] of
        |imageCopyTexture|.{{GPUImageCopyTexture/aspect}}.
    - If |texture|.{{GPUTexture/dimension}} is {{GPUTextureDimension/"2d"}}:
        - The [=array layer=] of |s| is &ge;
            |imageCopyTexture|.{{GPUImageCopyTexture/origin}}.[=GPUOrigin3D/z=] and &lt;
            |imageCopyTexture|.{{GPUImageCopyTexture/origin}}.[=GPUOrigin3D/z=] +
            |copySize|.[=GPUExtent3D/depthOrArrayLayers=].
</div>
